//============================================================================================
/**
 * @file	key_link_control.c
 * @brief	キーリンクコントローラ
 * @author	Nozomu Saito
 */
//============================================================================================
#include "common.h"
#include "key_link_control.h"
#include "poke_sel_cmn_def.h"

typedef enum {
	NONE_OVER,
	LEFT_OVER,
	RIGHT_OVER,
	UP_OVER,
	DOWN_OVER,
}DIR_OVER;

typedef struct KEY_LINK_DATA_tag {
	u8 Width;
	u8 Height;
	u8 IdxNum;
	u8 AreaID;
}KEY_LINK_DATA;

typedef struct KEY_LINK_PARAM_tag {
	s8 X;
	s8 Y;
	u8 Idx;
	u8 dummy;
}KEY_LINK_PARAM;

typedef struct OVER_INFO_tag{
	DIR_OVER DirOver;
	u8 Val;
	u8 dummy[3];
}OVER_INFO;

typedef void (*LINK_FUNC)( KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY );

typedef void (*OVER_FUNC)( KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);


typedef struct KEY_LINK_tag
{
	const KEY_LINK_DATA *Data;
	LINK_FUNC	LinkFunc;
	OVER_FUNC	OverFunc;
}KEY_LINK;

typedef struct KEY_LINK_CONT_tag
{
	u8 NowLinkTblIdx;
	u8 TblNum;
	u8 CancelOK;			//やめる許可
	u8 dummy;

	const u8 *CurrentBox;			//カレントボックスナンバー
	const KEY_LINK	*Tbl;
	KEY_LINK_PARAM *Param;
}KEY_LINK_CONT;

//リンク関数

static void  KeyLinkFuncBox(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);
static void  KeyLinkFuncExit(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);
static void  KeyLinkFuncDrop(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);

static void  KeyLinkFuncDropClose(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);
static void  KeyLinkFuncBoxName(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);
static void  KeyLinkFuncMyParty(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);

//オーバー時の出現決定関数
static void  KeyOverFuncBox(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);
static void  KeyOverFuncExit(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);
static void  KeyOverFuncDrop(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);
static void  KeyOverFuncDropClose(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);
static void  KeyOverFuncBoxName(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);
static void  KeyOverFuncMyParty(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo);

static DIR_OVER MoveFunc(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY);
static void ShiftArea(KEY_LINK_CONT_PTR pCntPtr, const LINK_AREA_ID inAreaID);
static void SetNewAreaPosition(KEY_LINK_CONT_PTR pCntPtr, const LINK_AREA_ID inAreaID, OVER_INFO *inInfo);

//ボックス内
static const KEY_LINK_DATA Box =  {
	6, 5, 30, LINK_AREA_BOX
};

//やめる
static const KEY_LINK_DATA Exit =  {
	1, 1, 1, LINK_AREA_EXIT
};

//ドロップエリア
static const KEY_LINK_DATA Drop =  {
	1, 3, 3, LINK_AREA_DROP
};

//ボックス名エリア
static const KEY_LINK_DATA BoxName =  {
	1, 1, 1, LINK_AREA_BOX_NAME
};

//ドロップエリア
static const KEY_LINK_DATA DropClose =  {
	1, 3, 3, LINK_AREA_DROP_CLOSE
};

//手持ちエリア
static const KEY_LINK_DATA MyParty =  {
	6, 1, 6, LINK_AREA_MY_PARTY
};


static const KEY_LINK KeyLinkTbls[] = {
	{&Box,		KeyLinkFuncBox, KeyOverFuncBox},
	{&Exit,		KeyLinkFuncExit, KeyOverFuncExit},
	{&Drop,		KeyLinkFuncDrop, KeyOverFuncDrop},
	{&DropClose,KeyLinkFuncDropClose, KeyOverFuncDropClose},
	{&BoxName,	KeyLinkFuncBoxName, KeyOverFuncBoxName},
	{&MyParty,	KeyLinkFuncMyParty, KeyOverFuncMyParty},

//	{PkthlnDrop,KeyLinkFuncPkthlnDrop},
};

//------------------------------------------------------------------
/**
 * @brief	ボックス　キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncBox(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);

	//オーバー情報作成
	info.DirOver = over;

	switch(over){
	case LEFT_OVER:
		info.Val = pParam->Y;//横ラインの数値（0〜4を入れる）
		//ドロップエリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP, &info);
		break;
	case RIGHT_OVER:
		info.Val = pParam->Y;//横ラインの数値（0〜4を入れる）
		//ドロップエリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP, &info);
		break;
	case UP_OVER:
		info.Val = pParam->X;//縦ラインの数値（0〜5を入れる）
		//ボックス選択エリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_BOX_NAME, &info);
		break;
	case DOWN_OVER:
		info.Val = pParam->X;//縦ラインの数値（0〜5を入れる）
		//ボックス選択エリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_BOX_NAME, &info);

		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	ボックス　オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncBox(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	//何処からきたか(来た方向)
	switch(inInfo->DirOver){
	case DOWN_OVER:	//下あふれで、上から来た(ボックス選択から)
		//記憶していればその位置。履歴がなくなっていたらきめうち
		pParam->X = 2;
		pParam->Y = 0;
		pParam->Idx = pParam->Y * pTbl->Width + pParam->X;
		break;
	case UP_OVER:	//上あふれで、下から来た(ボックス選択から)
		//記憶していればその位置。履歴がなくなっていたらきめうち
		pParam->X = 2;
		pParam->Y = 4;
		pParam->Idx = pParam->Y * pTbl->Width + pParam->X;
		break;
	case LEFT_OVER://左あふれで、右から来た
		pParam->X = 5;
		pParam->Y = inInfo->Val;
		pParam->Idx = pParam->Y * pTbl->Width + pParam->X;
		break;
	case RIGHT_OVER://右あふれで、左から来た
		pParam->X = 0;
		pParam->Y = inInfo->Val;
		pParam->Idx = pParam->Y * pTbl->Width;
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	「やめる」キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncExit(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);
	info.DirOver = over;
	info.Val = pParam->X;	//縦ラインのインデックスをセット

	switch(over){
	case UP_OVER:
		info.Val = 0;		//飛び先のX値
		//ドロップエリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP, &info);
		break;
	case LEFT_OVER:
		//現在のボックスナンバーが手持ちボックスかで分岐
		if (*pCntPtr->CurrentBox == MYPARTY_BOX){
			info.Val = 0;	//飛び先のY値
			//手持ちエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_MY_PARTY, &info);
		}else{
			info.Val = 4;	//飛び先のY値
			//ボックスエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_BOX, &info);
		}
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	「やめる」　オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncExit(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	pParam->X = 0;
	pParam->Y = 0;
	pParam->Idx = 0;
}

//------------------------------------------------------------------
/**
 * @brief	ドロップ　キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncDrop(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);
	info.DirOver = over;

	//飛び先Y座標セット
	if (pParam->Y == 0){
		info.Val = 0;
	}else if(pParam->Y == 1){
		info.Val = 2;
	}else{	//pParam->Y==2
		info.Val = 3;
	}

	switch(over){
	case LEFT_OVER:
		//現在のボックスナンバーが手持ちボックスかで分岐
		if (*pCntPtr->CurrentBox == MYPARTY_BOX){
			info.Val = 0;		//飛び先は必ずY値0（ボックス１段目）
			//手持ちエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_MY_PARTY, &info);
		}else{
			//ボックスエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_BOX, &info);
		}
		break;
	case RIGHT_OVER:
		//現在のボックスナンバーが手持ちボックスかで分岐
		if (*pCntPtr->CurrentBox == MYPARTY_BOX){
			info.Val = 0;		//飛び先は必ずY値0（ボックス１段目）
			//手持ちエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_MY_PARTY, &info);
		}else{
			//ボックスエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_BOX, &info);
		}
		break;
	case DOWN_OVER:
		//やめるエリアにシフト
		if (pCntPtr->CancelOK){
			//やめる
			SetNewAreaPosition(pCntPtr, LINK_AREA_EXIT, &info);
		}
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	ドロップエリア　動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncDrop(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	//何処からきたか(来た方向)
	switch(inInfo->DirOver){
	case UP_OVER:	//上あふれで、下から来た(やめるから)
		//インデックスセット(左側にある１番大きいインデックス値にする)
		pParam->Idx = ((pTbl->IdxNum-1)/pTbl->Width)*pTbl->Width;
		//座標セット
		pParam->X = pParam->Idx % pTbl->Width;
		pParam->Y = pParam->Idx / pTbl->Width;
		break;
	case LEFT_OVER://左あふれで、右から来た(ボックスの左あふれ)
	case RIGHT_OVER://右あふれで、左から来た(ボックスの右あふれ)
		if ( inInfo->Val < 2 ){
			pParam->Idx = 0;
		}else if( inInfo->Val > 2 ){
			pParam->Idx = 2;
		}else {
			pParam->Idx = 1;
		}
		//座標セット
		pParam->X = 0;
		pParam->Y = pParam->Idx;
		break;
	};
}

//------------------------------------------------------------------
/**
 * @brief	ドロップ後エリア　キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncDropClose(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);
	info.DirOver = over;
	info.Val = 0;	//付加情報は特になし
	switch(over){
	case UP_OVER:
		//回り込み
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP_CLOSE, &info);
		break;
	case DOWN_OVER:
		//回り込み
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP_CLOSE, &info);
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncDropClose(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	//他のエリアから飛んでくることはない
	;
}

//------------------------------------------------------------------
/**
 * @brief	ボックス　キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncBoxName(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);
	info.DirOver = over;
	info.Val = pParam->X;	//縦ラインのインデックスをセット
	switch(over){
	case LEFT_OVER:
		break;
	case RIGHT_OVER:
		break;
	case UP_OVER:
		//現在のボックスナンバーが手持ちボックスかで分岐
		if (*pCntPtr->CurrentBox == MYPARTY_BOX){
			//手持ちエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_MY_PARTY, &info);
		}else{
			//ボックスエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_BOX, &info);
		}
		break;
	case DOWN_OVER:
		//現在のボックスナンバーが手持ちボックスかで分岐
		if (*pCntPtr->CurrentBox == MYPARTY_BOX){
			//手持ちエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_MY_PARTY, &info);
		}else{
			//ボックスエリアにシフト
			SetNewAreaPosition(pCntPtr, LINK_AREA_BOX, &info);
		}
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	ボックス　オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncBoxName(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	pParam->X = 0;
	pParam->Y = 0;
	pParam->Idx = 0;
}

//------------------------------------------------------------------
/**
 * @brief	手持ち　キーリンク動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyLinkFuncMyParty(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	DIR_OVER over;
	OVER_INFO info;
	over = MoveFunc(pCntPtr, pParam, pTbl, inX, inY);
	info.DirOver = over;
	info.Val = pParam->X;	//縦ラインのインデックスをセット
	switch(over){
	case LEFT_OVER:
		info.Val = pParam->Y;//横ラインの数値（0〜4を入れる）
		//ドロップエリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP, &info);
		break;
	case RIGHT_OVER:
		info.Val = pParam->Y;//横ラインの数値（0〜4を入れる）
		//ドロップエリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_DROP, &info);
		break;
	case UP_OVER:
		info.Val = pParam->X;//縦ラインの数値（0〜5を入れる）
		//ボックス選択エリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_BOX_NAME, &info);
		break;
	case DOWN_OVER:
		info.Val = pParam->X;//縦ラインの数値（0〜5を入れる）
		//ボックス選択エリアにシフト
		SetNewAreaPosition(pCntPtr, LINK_AREA_BOX_NAME, &info);
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	手持ち　オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inInfo				オーバー情報
 *
 * @return	none
 */
//------------------------------------------------------------------
static void KeyOverFuncMyParty(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl,
						OVER_INFO *inInfo)
{
	//何処からきたか(来た方向)
	switch(inInfo->DirOver){
	case DOWN_OVER:	//下あふれで、上から来た(ボックス選択から)
	case UP_OVER:	//上あふれで、下から来た(ボックス選択から)
		//記憶していればその位置。履歴がなくなっていたらきめうち
		pParam->X = 2;
		pParam->Y = 0;
		pParam->Idx = pParam->Y * pTbl->Width + pParam->X;
		break;
	case LEFT_OVER://左あふれで、右から来た
		pParam->X = 5;
		pParam->Y = 0;
		pParam->Idx = pParam->Y * pTbl->Width + pParam->X;
		break;
	case RIGHT_OVER://右あふれで、左から来た
		pParam->X = 0;
		pParam->Y = 0;
		pParam->Idx = pParam->Y * pTbl->Width;
		break;
	}
}

//------------------------------------------------------------------
/**
 * @brief	オーバー時動作関数
 *
 * @param	pCntPtr				管理ポインタ
 * @param	pParam				パラム
 * @param	pTbl				リンクテーブル
 * @param	inX					X座標
 * @param	inY					Y座標
 *
 * @return	DIR_OVER			オーバー方向
 */
//------------------------------------------------------------------
static DIR_OVER MoveFunc(KEY_LINK_CONT_PTR pCntPtr,
						KEY_LINK_PARAM *pParam,
						const KEY_LINK_DATA *pTbl, const s8 inX, const s8 inY)
{
	u8 idx;
	s8 x,y;
	DIR_OVER over = NONE_OVER;
	u8 w = pTbl->Width;
	u8 h = pTbl->Height;

	//座標更新
	if (inX != 0){
		x = pParam->X + inX;
		y = pParam->Y;
		if (x < 0){
			//左オーバー
			over = LEFT_OVER;
		}else if(x >= w){
			//右オーバー
			over = RIGHT_OVER;
		}else{
			//インデックスオーバーチェック
			idx = y*w+x;
			if ( idx >= pTbl->IdxNum ){
				//配置的に右オーバー扱い
				over = RIGHT_OVER;
			}
		}

		//位置とインデックス更新
		if (over == NONE_OVER){
			pParam->X = x;
			pParam->Idx = y*w+x;
		}else {
			OS_Printf("OVER!!:%d\n",over);
			return over;
		}
	}

	if (inY != 0){
		x = pParam->X;
		y = pParam->Y + inY;

		if (y < 0){
			//上オーバー
			over = UP_OVER;
		}else if(y >= h){
			//下オーバー
			over = DOWN_OVER;
		}else{
			//インデックスオーバーチェック
			idx = y*w+x;
			if ( idx >= pTbl->IdxNum ){
				//配置的に下オーバー扱い
				over = DOWN_OVER;
			}
		}

		//位置とインデックス更新
		if (over == NONE_OVER){
			pParam->Y = y;
			pParam->Idx = y*w+x;
		}else {
			OS_Printf("OVER!!:%d\n",over);
			return over;
		}
	}
	return NONE_OVER;
}

//------------------------------------------------------------------
/**
 * @brief	エリアのシフト
 *
 * @param	pCntPtr				管理ポインタ
 * @param	inAreaID			エリアID
 *
 * @return	none
 */
//------------------------------------------------------------------
static void ShiftArea(KEY_LINK_CONT_PTR pCntPtr, const LINK_AREA_ID inAreaID)
{
	int i;
	for(i=0;i<pCntPtr->TblNum;i++){
		if (pCntPtr->Tbl[i].Data->AreaID == inAreaID){
			pCntPtr->NowLinkTblIdx = i;
			break;
		}
	}
}

//------------------------------------------------------------------
/**
 * @brief	新エリアの位置セット
 *
 * @param	pCntPtr				管理ポインタ
 * @param	inAreaID			エリアID
 * @param	inInfo				オーバー時の出現情報
 *
 * @return	KEY_LINK_CONT_PTR		管理ポインタ
 */
//------------------------------------------------------------------
static void SetNewAreaPosition(KEY_LINK_CONT_PTR pCntPtr, const LINK_AREA_ID inAreaID, OVER_INFO *inInfo)
{
	OVER_FUNC	over_func;
	KEY_LINK_PARAM *param;
	const KEY_LINK_DATA   *data;

	ShiftArea(pCntPtr, inAreaID);
	//現在アクティブなコントロールエリアを取得
	param = &pCntPtr->Param[ pCntPtr->NowLinkTblIdx ];
	data = pCntPtr->Tbl[ pCntPtr->NowLinkTblIdx ].Data;

	//エリアシフト後の場所決定
	over_func = pCntPtr->Tbl[ pCntPtr->NowLinkTblIdx ].OverFunc;
	over_func(pCntPtr, param, data, inInfo);

	OS_Printf("エリア変更::%d\n",pCntPtr->NowLinkTblIdx);
	OS_Printf("座標XY=%d,%d::INDEX=%d\n",param->X,param->Y,param->Idx);
}

//------------------------------------------------------------------
/**
 * @brief	メモリアロケーション
 * @param	inHeapID		ヒープ
 * @param	inCurrentBox		カレントボックスポインタ
 *
 * @return	KEY_LINK_CONT_PTR		管理ポインタ
 */
//------------------------------------------------------------------
KEY_LINK_CONT_PTR KeyLink_Alloc(const int inHeapID, const u8 *inCurrentBox)
{
	KEY_LINK_CONT_PTR ptr;
	ptr = sys_AllocMemory(inHeapID, sizeof(KEY_LINK_CONT));
	//ゼロクリア
	memset(ptr, 0, sizeof(KEY_LINK_CONT));
	ptr->TblNum = NELEMS(KeyLinkTbls);
	ptr->Param = sys_AllocMemory(inHeapID, sizeof(KEY_LINK_PARAM)*ptr->TblNum);
	memset(ptr->Param, 0, sizeof(KEY_LINK_PARAM)*ptr->TblNum);
	//ゼロクリア

	//カレントボックスポインタセット
	ptr->CurrentBox = inCurrentBox;
	return ptr;
}

//------------------------------------------------------------------
/**
 * @brief	初期化関数
 * @param	pCntPtr		管理ポインタ
 * @param	inCancelOK	キャンセルできるか？
 *
 * @return	none
 */
//------------------------------------------------------------------
void KeyLink_Init(KEY_LINK_CONT_PTR ptr, const u8 inCancelOK)
{
	ptr->NowLinkTblIdx = 0;

	ptr->Tbl =  KeyLinkTbls;
	ptr->CancelOK = inCancelOK;
}

//------------------------------------------------------------------
/**
 * @brief	解放関数
 * @param	pCntPtr		管理ポインタ
 *
 * @return	none
 */
//------------------------------------------------------------------
void KeyLink_Free(KEY_LINK_CONT_PTR pCntPtr)
{
	sys_FreeMemoryEz(pCntPtr->Param);
	sys_FreeMemoryEz(pCntPtr);
}

//------------------------------------------------------------------
/**
 * @brief	現在位置のセット
 * @param	pCntPtr		管理ポインタ
 * @param	inAreaID	エリアID
 * @param	inIdx		インデックス
 *
 * @return	none
 */
//------------------------------------------------------------------
void KeyLink_SetPosition(KEY_LINK_CONT_PTR pCntPtr, const LINK_AREA_ID inAreaID, const u8 inIdx)
{
	KEY_LINK_PARAM *param;
	const KEY_LINK_DATA   *data;

	OS_Printf("idx=%d\n",inIdx);

	ShiftArea(pCntPtr, inAreaID);
	//現在アクティブなコントロールエリアを取得
	param = &pCntPtr->Param[ pCntPtr->NowLinkTblIdx ];
	data = pCntPtr->Tbl[ pCntPtr->NowLinkTblIdx ].Data;

	//指定インデックスの場所に移動
	GF_ASSERT(inIdx < data->IdxNum);
	param->Idx = inIdx;
	if (param->Idx >= data->IdxNum){
		param->Idx = 0;
	}
	//座標計算
	param->X = param->Idx % data->Width;
	param->Y = param->Idx /	data->Width;
}

//------------------------------------------------------------------
/**
 * @brief	現在カーソル位置の移動
 * @param	pCntPtr		管理ポインタ
 * @param	inX			エリア内Ｘ
 * @param	inY			エリア内Ｙ
 * @return	BOOL		カーソルの移動が発生した場合:TRUE
 */
//------------------------------------------------------------------
BOOL KeyLink_MovePointPosition(KEY_LINK_CONT_PTR pCntPtr, const s8 inX, const s8 inY)
{
	KEY_LINK_PARAM *param;
	const KEY_LINK   *link;
	LINK_FUNC link_func;
	u8 old_area;
	u8 old_idx;

	//現在アクティブなコントロールエリアを取得
	param = &pCntPtr->Param[ pCntPtr->NowLinkTblIdx ];
	link = &pCntPtr->Tbl[ pCntPtr->NowLinkTblIdx ];

	old_area = pCntPtr->NowLinkTblIdx;
	old_idx = param->Idx;

	//リンク関数取得
	link_func = link->LinkFunc;

	link_func( pCntPtr, param, link->Data, inX, inY );

	OS_Printf("座標XY=%d,%d::INDEX=%d\n",param->X,param->Y,param->Idx);

	if (old_area != pCntPtr->NowLinkTblIdx){
		return TRUE;
	}
	if (old_idx != param->Idx){
		return TRUE;
	}
	return FALSE;
}

//------------------------------------------------------------------
/**
 * @brief	現在のリンクエリアIDを取得
 *
 * @param	pCntPtr		管理ポインタ
 * @return	LINK_AREA_ID		リンクエリアID
 */
//------------------------------------------------------------------
LINK_AREA_ID KeyLink_GetLinkAreaID(KEY_LINK_CONT_PTR pCntPtr)
{
	const KEY_LINK_DATA   *data;
	data = pCntPtr->Tbl[ pCntPtr->NowLinkTblIdx ].Data;

	return data->AreaID;
}

//------------------------------------------------------------------
/**
 * @brief	エリア内インデックスの取得
 *
 * @param	pCntPtr		管理ポインタ
 * @return	u8		インデックス
 */
//------------------------------------------------------------------
u8 KeyLink_GetIndex(KEY_LINK_CONT_PTR pCntPtr)
{
	KEY_LINK_PARAM *param;
	//現在アクティブなコントロールエリアを取得
	param = &pCntPtr->Param[ pCntPtr->NowLinkTblIdx ];

	return param->Idx;
}